
// WebGUIDoc.cpp : implementation of the CWebGUIDoc class
//

#include "stdafx.h"
#include "WebGUI.h"

#include "WebGUIDoc.h"
#include "MainFrm.h"
#include <stdio.h>
#include "winsock2.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CWebGUIDoc

IMPLEMENT_DYNCREATE(CWebGUIDoc, CDocument)

BEGIN_MESSAGE_MAP(CWebGUIDoc, CDocument)
END_MESSAGE_MAP()


// CWebGUIDoc construction/destruction

UINT ListenThread (PVOID p);
CWebGUIDoc::CWebGUIDoc()
{

	// read IP address and port number for FM connection
	m_nPort = GetPrivateProfileInt("General", "Port", 15001 , ".\\Settings.ini") ;
	GetPrivateProfileString("General","IP", "155.98.39.115", m_strIP.GetBuffer(100), 100 ,  ".\\Settings.ini") ;
	m_strIP.ReleaseBuffer();


	m_bConnected  = FALSE ;
	m_bRecording = FALSE;

	// The socket thread which
	m_hNodeMutex = CreateMutex(NULL, FALSE, NULL);

	// Setup Socket API
	InitWSA();

	m_bShouldUpdate = FALSE ;
	
	
	// start the socket thread which communicate with FM
	AfxBeginThread( ListenThread, this ) ;

}

CWebGUIDoc::~CWebGUIDoc()
{
	ReleaseMutex(m_hNodeMutex);
}

BOOL CWebGUIDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	// TODO: add reinitialization code here
	// (SDI documents will reuse this document)

	return TRUE;
}




// CWebGUIDoc serialization

void CWebGUIDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: add storing code here
	}
	else
	{
		// TODO: add loading code here
	}
}


// CWebGUIDoc diagnostics

#ifdef _DEBUG
void CWebGUIDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CWebGUIDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG


// CWebGUIDoc commands


UINT ListenThread (PVOID p)
{

	CWebGUIDoc *pDoc = (CWebGUIDoc *)p ;

	Sleep(2000);


	while(TRUE)
	{
		pDoc->GetPacket();
		Sleep(100);
	}
	

}

BOOL CWebGUIDoc::InitWSA()
{
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2,2), &wsaData);

	return TRUE ;
}

void CWebGUIDoc::ProcessNewPacket()
{
	// To detect if a node has left the system
	for (int nOld=0;nOld<m_aNodes.GetCount();nOld++)
	{
		BOOL bFound = FALSE ;
		for (int nNew=0; nNew<m_aNodesNew.GetCount() ; nNew++)
		{
			if (m_aNodes[nOld].strIP == m_aNodesNew[nNew].strIP)
			{
				bFound = TRUE ;
			}
		}
		if (!bFound)
		{
			CString strEvent ;
			strEvent.Format("Node '%s' left the system" , m_aNodes[nOld].strIP ) ;
			AddLog("Warning", strEvent) ;
		}
	}

	// To detect if a new node has joined 
	for (int nNew=0;nNew<m_aNodesNew.GetCount();nNew++)
	{
		BOOL bFound = FALSE ;
		for (int nOld=0; nOld<m_aNodes.GetCount() ; nOld++)
		{
			if (m_aNodes[nOld].strIP == m_aNodesNew[nNew].strIP)
			{
				bFound = TRUE ;
			}
		}
		if (!bFound)
		{
			CString strEvent ;
			strEvent.Format("Node '%s' enters the system" , m_aNodesNew[nNew].strIP ) ;
			AddLog("Report", strEvent) ;
		}
	}


	m_aNodes.RemoveAll() ;
	m_aNodes.Copy(m_aNodesNew) ;

	RefreshNodeList() ;
}

void CWebGUIDoc::RefreshNodeList()
{
	GetFrame()->m_wndNodeListPane.UpdateList( m_aNodes ) ;
	GetFrame()->m_wndGraphPane.UpdateList( m_aNodes ) ;
	
	// Record the newly arrived data if the recording is enabled
	if(m_bRecording)
	{
		SYSTEMTIME st ;
		GetLocalTime(&st);
		for (int n=0;n<m_aNodes.GetCount();n++)
		{
			CString strFileName ;
			strFileName.Format("LOG_%s.txt", m_aNodes[n].strIP) ;
			FILE *fp = fopen(strFileName, "a+t") ;
			if (fp!=NULL)
			{
				fprintf(fp,"%04d/%02d/%02d-%02d:%02d:%02d\t%s\t%s\t%s\t%s\n",
					st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond ,
					m_aNodes[n].strCPU , 
					m_aNodes[n].strRequestCount, 
					m_aNodes[n].strMemFree , 
					m_aNodes[n].strMemUsed 
					);
				fclose(fp);
			}
		}
	}
}
void CWebGUIDoc::AddLog( CString strEventType , CString strDesciption )
{
	GetFrame()->m_wndEventLogPane.AddLog( strEventType, strDesciption ) ;
	
}
#include "WebGUIView.h"
CMainFrame *CWebGUIDoc::GetFrame()
{
	POSITION pos =  GetFirstViewPosition() ;
	CView *pView = GetNextView(pos) ;
	if (pView)
	{
		return ((CWebGUIView*)pView)->m_pFrame ;
	}
	return NULL ;

}

BOOL CWebGUIDoc::GetPacket()
{
	SOCKET Socket;   // windows socket 
	sockaddr_in RecvAddr;  // address of the party
	int Port = m_nPort; // port number
	
	char RecvBuf[10240];  // communication buffer
	int  BufLen = 10240;
	
	sockaddr_in SenderAddr; // address of the party
	int SenderAddrSize = sizeof(SenderAddr);

	//-----------------------------------------------
	// Create a datagrams socket
	Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	
	bind(Socket, (SOCKADDR *) &RecvAddr, sizeof(RecvAddr));
	
	struct timeval tv;

	tv.tv_sec = 1;  /* 1 Secs Timeout */
	setsockopt(Socket, SOL_SOCKET, SO_RCVTIMEO,(const char *)&tv,sizeof(struct timeval));
	while(1)
	{

		Sleep(100);
	// First send the request to FM	
	{
		RecvAddr.sin_family = AF_INET;
		RecvAddr.sin_port = htons(Port);
		RecvAddr.sin_addr.s_addr = inet_addr(m_strIP);

		//---------------------------------------------
		// Send a datagram to the receiver

		char buf[1000]="4\n";   // this command tell FM to send us a new list of nodes
		int nRes = sendto(Socket, 
			buf, 
			2, 
			0, 
			(SOCKADDR *) &RecvAddr, 
			sizeof(RecvAddr));

	}


	RecvAddr.sin_family = AF_INET;
	RecvAddr.sin_port = htons(Port);
	RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);

	Sleep(100);
	// bind socket to the specified port and listen for the FM

	memset( RecvBuf , 0 , 1000) ;
//	Sleep(1000);
	int nCount = recvfrom(Socket, 
		RecvBuf, 
		BufLen, 
		0, 
		(SOCKADDR *)&SenderAddr, 
		&SenderAddrSize);

	RecvBuf[nCount]= NULL ;

	if (nCount<2)
	{
		// unknown packet
		continue;
	}

	m_strLastPacket = RecvBuf ;
	
	// decode the new packet
	ReadPacket(m_strLastPacket);
	
	GetLocalTime(&m_stLastUpdate);
	if (!m_bConnected)
	{
		m_bConnected = TRUE ;
		OnChangeConnection();		
		m_stStartTime = m_stLastUpdate;
	}
	
	// update all views with the new data
	ProcessNewPacket();
	m_bShouldUpdate = TRUE ;
	}

	return TRUE ;
}

void CWebGUIDoc::OnChangeConnection()
{
	if (m_bConnected)
	{
		AddLog("Report", "Connected to FM") ;
	}
	else
	{
		m_aNodes.RemoveAll();
		AddLog("Error", "Disconnected from FM") ;
		GetFrame()->m_wndNodeListPane.m_ctrlNodeList.DeleteAllItems() ;
	}
	m_bShouldUpdate = TRUE ;
}

// decode the content of packet string received from FM
void CWebGUIDoc::ReadPacket(CString strPacket)
{
	m_aNodesNew.RemoveAll() ;
	int nSender ;
	sscanf(strPacket,"%d-", &nSender ) ;
	
	if (nSender!=2) // if the sender is not fault manager returns
	{
	//	return ;
	}
	
	int nStart = strPacket.Find('-') ;
	if (nStart<0)
	{
		return ;
	}

	strPacket = strPacket.Mid(nStart+1) ;
	BOOL bFound = TRUE ;
	while(bFound)
	{
		SERVER_NODE sn ;
		int nEnd = strPacket.Find("---") ;
		if (nEnd<0)
		{
			break ;
		}
		CString str = strPacket.Left(nEnd);
		
		int nCurPos = 0 ;
		sn.strIP = str.Tokenize(",",nCurPos);

		sn.strType = str.Tokenize(",",nCurPos);
		sn.strCPU = str.Tokenize(",",nCurPos);
		long l = 999 - atol(sn.strCPU) ;
		l = max(0,l);
		sn.strCPU.Format("%03d",l);
		
		sn.strMemUsed = str.Tokenize(",",nCurPos);
		sn.strMemFree = str.Tokenize(",",nCurPos);
		sn.strRequestCount = str.Tokenize(",",nCurPos);
		sn.strLastRequestTime = str.Tokenize(",",nCurPos);

		m_aNodesNew.Add(sn);

		strPacket = strPacket.Mid(nEnd+3);

	}

}